package com.anry.weatherforecast.utils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.security.MessageDigest;

/**
 * 修复的阿里云API网关签名工具类
 */
public class FixedAliYunSignatureUtil {
    
    private static final String HMAC_SHA256 = "HmacSHA256";
    
    /**
     * 计算签名（根据服务器返回的格式修复）
     */
    public static String calculateSignature(String secret, 
                                          String method,
                                          String accept,
                                          String contentMD5,
                                          String contentType,
                                          String date,
                                          Map<String, String> headers,
                                          String path,
                                          Map<String, String> queryParams,
                                          Map<String, String> formParams) throws Exception {
        
        // 1. 构造待签名字符串（使用服务器要求的格式）
        String stringToSign = buildStringToSign(method, accept, contentMD5, 
                                              contentType, date, headers, 
                                              path, queryParams, formParams);
        
        System.out.println("待签名字符串: " + stringToSign);
        
        // 2. 计算HMAC-SHA256签名
        Mac hmacSha256 = Mac.getInstance(HMAC_SHA256);
        byte[] keyBytes = secret.getBytes(StandardCharsets.UTF_8);
        hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, HMAC_SHA256));
        byte[] signData = hmacSha256.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
        
        // 3. Base64编码
        String signature = Base64.getEncoder().encodeToString(signData);
        System.out.println("计算得到的签名: " + signature);
        
        return signature;
    }
    

    /**
     * 构造待签名字符串（根据阿里云API网关文档修正）
     */
    private static String buildStringToSign(String method,
                                            String accept,
                                            String contentMD5,
                                            String contentType,
                                            String date,
                                            Map<String, String> headers,
                                            String path,
                                            Map<String, String> queryParams,
                                            Map<String, String> formParams) {

        StringBuilder sb = new StringBuilder();

        // HTTPMethod
        sb.append(method.toUpperCase()).append("\n");

        // Accept
        sb.append(accept != null ? accept : "").append("\n");

        // Content-MD5
        sb.append(contentMD5 != null ? contentMD5 : "").append("\n");

        // Content-Type
        sb.append(contentType != null ? contentType : "").append("\n");

        // Date
        sb.append(date != null ? date : "").append("\n");

        // Headers（使用\n分隔）
        if (headers != null && !headers.isEmpty()) {
            sb.append(buildHeadersString(headers)).append("\n");
        } else {
            sb.append("\n"); // 即使Headers为空也要添加换行符
        }

        // URL
        sb.append(buildUrlString(path, queryParams, formParams));

        return sb.toString();
    }


    /**
     * 构建Headers签名字符串（使用\n分隔）
     */
    private static String buildHeadersString(Map<String, String> headers) {
        // 过滤掉不参与签名的Header
        Map<String, String> filteredHeaders = new HashMap<>();
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            String key = entry.getKey();
            if (key.startsWith("X-Ca-") &&
                    !key.equals("X-Ca-Signature") &&
                    !key.equals("X-Ca-Signature-Headers")) {
                filteredHeaders.put(key, entry.getValue());
            }
        }

        // 按字典序排序
        List<String> sortedKeys = new ArrayList<>(filteredHeaders.keySet());
        Collections.sort(sortedKeys);

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < sortedKeys.size(); i++) {
            if (i > 0) {
                sb.append("\n");  // 使用 \n 分隔符
            }
            String key = sortedKeys.get(i);
            String value = filteredHeaders.get(key);
            // 如果Value为空，也要保留Key和冒号
            sb.append(key).append(":").append(value != null ? value : "");
        }

        return sb.toString();
    }



    /**
     * 构建URL字符串（Path + Query + Form参数）
     */
    private static String buildUrlString(String path,
                                       Map<String, String> queryParams,
                                       Map<String, String> formParams) {

        // 合并Query和Form参数
        Map<String, String> allParams = new HashMap<>();
        if (queryParams != null) {
            allParams.putAll(queryParams);
        }
        if (formParams != null) {
            allParams.putAll(formParams);
        }

        if (allParams.isEmpty()) {
            return path;
        }

        // 按字典序排序参数
        List<String> sortedKeys = new ArrayList<>(allParams.keySet());
        Collections.sort(sortedKeys);

        StringBuilder sb = new StringBuilder(path);
        sb.append("?");

        for (int i = 0; i < sortedKeys.size(); i++) {
            if (i > 0) {
                sb.append("&");
            }
            String key = sortedKeys.get(i);
            String value = allParams.get(key);
            sb.append(key);
            if (value != null && !value.isEmpty()) {
                sb.append("=").append(value);
            }
        }

        return sb.toString();
    }

    /**
     * 计算Content-MD5
     */
    public static String calculateContentMD5(String body) throws Exception {
        if (body == null || body.isEmpty()) {
            return "";
        }
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] digest = md.digest(body.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(digest);
    }
    
    /**
     * 获取参与签名的Header名称列表
     */
    public static String getSignatureHeaders(Map<String, String> headers) {
        List<String> headerNames = new ArrayList<>();
        for (String key : headers.keySet()) {
            if (key.startsWith("X-Ca-") && 
                !key.equals("X-Ca-Signature") && 
                !key.equals("X-Ca-Signature-Headers")) {
                headerNames.add(key);
            }
        }
        Collections.sort(headerNames);
        return String.join(",", headerNames);
    }



    /**
     * 生成UUID作为Nonce
     */
    public static String generateNonce() {
        return UUID.randomUUID().toString();
    }
    
    /**
     * 获取当前时间戳（毫秒）
     */
    public static String getCurrentTimestamp() {
        return String.valueOf(System.currentTimeMillis());
    }
}